package fr.jade.fraclite.control.lifecycle;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.fractal.api.control.ContentController;
import org.objectweb.fractal.api.control.IllegalBindingException;
import org.objectweb.fractal.api.control.IllegalLifeCycleException;
import org.objectweb.fractal.api.control.LifeCycleController;
import org.objectweb.fractal.api.factory.InstantiationException;
import org.objectweb.fractal.api.type.ComponentType;
import org.objectweb.fractal.api.type.InterfaceType;
import org.objectweb.fractal.util.Fractal;

import fr.jade.fraclite.InitializationContext;
import fr.jade.fraclite.api.Controller;
import fr.jade.fraclite.control.binding.ChainedIllegalBindingException;

public class CheckLifeCycleController implements Controller,
		LifeCycleController {

	protected String state = LifeCycleController.STOPPED;

	protected ContentController cc = null;

	protected LifeCycleController innerImpl = null;

	protected BindingController bc = null;

	protected Component thisComp = null;

	public void initFcController(final InitializationContext ic)
			throws InstantiationException {
		if (ic.content instanceof LifeCycleController) {
			innerImpl = (LifeCycleController) ic.content;
		}
		try {
			cc = (ContentController) ic.getInterface("content-controller");
		} catch (InstantiationException ignored) {
		}

		try {
			bc = (BindingController) ic.getInterface("binding-controller");
		} catch (InstantiationException ignored) {
		}

		try {
			thisComp = (Component) ic.getInterface("component");
		} catch (InstantiationException ignored) {
		}

		state = LifeCycleController.STOPPED;
	}

	public String getFcState() {
		if (innerImpl == null) {
			return state;
		} else {
			return innerImpl.getFcState();
		}
	}

	public void startFc() throws IllegalLifeCycleException {
		if (cc != null) {
			for (Component sub : cc.getFcSubComponents()) {
				try {
					try {
						checkFcMandatoryInterfaces(sub);
					} catch (IllegalBindingException e) {
						throw new ChainedIllegalLifeCycleException(e, sub,
								"Cannot start the component");
					}

					LifeCycleController lcc = Fractal
							.getLifeCycleController(sub);
					lcc.startFc();
				} catch (NoSuchInterfaceException ignored) {
				}
			}
		}

		if (bc != null) {
			try {
				checkFcMandatoryInterfaces(thisComp);
			} catch (IllegalBindingException e) {
				throw new ChainedIllegalLifeCycleException(e, thisComp,
						"Cannot start the component");
			}
		}

		if (innerImpl == null) {
			state = LifeCycleController.STARTED;
		} else {
			innerImpl.startFc();
		}
	}

	public void stopFc() throws IllegalLifeCycleException {
		if (cc != null) {
			for (Component sub : cc.getFcSubComponents()) {
				try {
					LifeCycleController lcc = Fractal
							.getLifeCycleController(sub);
					lcc.stopFc();
				} catch (NoSuchInterfaceException ignored) {
				}
			}
		}
		if (innerImpl == null) {
			state = LifeCycleController.STOPPED;
		} else {
			innerImpl.stopFc();
		}
	}

	public void checkFcMandatoryInterfaces(final Component c)
			throws IllegalBindingException {

		BindingController bc;
		try {
			bc = (BindingController) c.getFcInterface("binding-controller");
		} catch (NoSuchInterfaceException e) {
			return;
		}

		ComponentType compType = (ComponentType) c.getFcType();
		InterfaceType[] interfaces = compType.getFcInterfaceTypes();

		for (int i = 0; i < interfaces.length; i++) {
			if (interfaces[i].isFcClientItf()
					&& !interfaces[i].isFcOptionalItf()) {
				Object sItf;
				try {
					sItf = bc.lookupFc(interfaces[i].getFcItfName());
				} catch (NoSuchInterfaceException e) {
					continue;
				}
				if (sItf == null) {
					throw new ChainedIllegalBindingException(null, c, null,
							interfaces[i].getFcItfName(), null,
							"Mandatory client interface unbound");
				}
			}
		}
	}

}
